package com.cooperate.fly.controller;

import com.cooperate.fly.bo.Case;
import com.cooperate.fly.bo.CaseWithBLOBs;
import com.cooperate.fly.bo.Field;
import com.cooperate.fly.bo.Schema;
import com.cooperate.fly.mapper.CaseMapper;
import com.cooperate.fly.mapper.FieldMapper;
import com.cooperate.fly.mapper.SchemaMapper;
import com.cooperate.fly.service.buildDB.BuildCaseService;
import com.cooperate.fly.util.FileUtil;
import com.cooperate.fly.util.ZipUtil;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import com.cooperate.fly.web.Result;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by baobao on 2016/5/2.
 */
@Controller
@RequestMapping("/upload")
public class UploadController extends BaseController {

    @Resource
    BuildCaseService buildCaseService;


    @Value("#{propertiesReader['filePath']}")
    public String FilePath;
    @Value("#{propertiesReader['imagePath']}")
    public String imagePath;
    @Value("#{propertiesReader['threeDPath']}")
    public String threeDPath;
    @Value("#{propertiesReader['videoPath']}")
    public String videoPath;
    @Value("#{propertiesReader['caseTempPath']}")
    public String caseTempPath;
    @Value("#{propertiesReader['casesTempPath']}")
    public String casesTempPath;
    @Value("#{propertiesReader['basePath']}")
    public String basePath;

    @Value("#{propertiesReader['case_catalog_type']}")
    public int caseCatalogType;
    @Value("#{propertiesReader['case_data_type']}")
    public int caseDataType;

    @Autowired
    CaseMapper caseMapper;
    @Autowired
    FieldMapper fieldMapper;

    @RequestMapping(value="/uploadPic", method=RequestMethod.POST)
    public void uploadImg(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) throws IOException {
        upload(multipartRequest, response, imagePath);
    }

    @RequestMapping(value="/uploadFile", method=RequestMethod.POST)
    public void uploadFile(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) throws IOException{
        upload(multipartRequest, response, FilePath);
    }

    @RequestMapping(value="/upload3D", method=RequestMethod.POST)
    public void upload3D(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) throws IOException {
        upload(multipartRequest, response, threeDPath);
    }

    @RequestMapping(value="/uploadVideo", method=RequestMethod.POST)
    public void uploadVideo(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) throws IOException{
        upload(multipartRequest, response, videoPath);
    }

    @RequestMapping(value="/uploadCase", method=RequestMethod.POST)
    public void uploadCase(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) throws IOException{
        File file = new File(caseTempPath);
        if(!file.exists()) file.mkdir();
        upload(multipartRequest, response, caseTempPath);
    }

    @RequestMapping(value="/uploadCases", method=RequestMethod.POST)
    public void uploadCases(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) throws IOException{
        File file = new File(casesTempPath);
        if(!file.exists()) file.mkdir();
        upload(multipartRequest, response, casesTempPath);
    }

    @RequestMapping(value="/readCases", method =RequestMethod.GET)
    @ResponseBody
    public Result readCases(@RequestParam(value="filename", required=true) String filename, @RequestParam(value="parentId", required=true) String pId){
        //clearZipAndDir(casesTempPath);
        String path = casesTempPath + File.separator;
        filename = path + filename;
        System.out.println(filename);
        //unzip
        ZipUtil.unZipFiles(filename, path);
        //each dir is a caseNode, catalog or case, create case and insert into database
        File f = null;
        File[] paths = null;
        int parentId = Integer.parseInt(pId);
        Queue<File> file_queue = new LinkedList<File>();
        Queue<Integer> parentId_queue = new LinkedList<Integer>();
        try{
            f = new File(path);
            paths = f.listFiles();
            for(File file : paths){
//                System.out.println(paths.length);
                if(file.isDirectory()) {
                    file_queue.offer(file);
                    parentId_queue.offer(parentId);
                }
            }
            while(!file_queue.isEmpty()){
                File file = file_queue.poll();
                int parent_temp = parentId_queue.poll();
                if(file.getName().endsWith("_catalog")){
                    //create catalog insert into database
                    Case _case = new CaseWithBLOBs();
                    _case.setName(file.getName().substring(0,file.getName().lastIndexOf("_catalog")));
                    _case.setParentId(parent_temp);
                    _case.setType(caseCatalogType);
                    Result res = buildCaseService.createCaseNode(_case);
                    if(!res.isSuccessful()){
                        return res;
                    }
                    parent_temp = (Integer) res.getData();
                    //push subdir to stack
                    File[] subDir = file.listFiles();
                    for(File subfile : subDir){
                        file_queue.offer(subfile);
                        parentId_queue.offer(parent_temp);
                    }
                }else if(file.getName().endsWith("_case")){
                    //create case insert into database
                    Case _case = new CaseWithBLOBs();
                    _case.setName(file.getName().substring(0,file.getName().lastIndexOf("_case")));
                    _case.setParentId(parent_temp);
                    _case.setType(caseDataType);
                    Result res = buildCaseService.createCaseNode(_case);
                    if(!res.isSuccessful()){
                        return res;
                    }
                    //readCase
                    int caseId = (Integer)res.getData();
//                    readOneOfCases(file.getAbsolutePath()+File.separator+_case.getName(), caseId);
                    readOneOfCases(file.getAbsolutePath(), caseId);
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        //set result message as tree json to update tree
        Result res = new Result();
        String json = buildCaseService.getImportTreeJson(Integer.parseInt(pId));
        res.setMessage(json);
        f = new File(path);
        FileUtil.deleteAll(f);
        if(!f.exists())
            f.mkdir();
        return res;
    }

    @RequestMapping(value="/readCase",method=RequestMethod.GET)
    @ResponseBody
    public Result readCase(@RequestParam(value="filename", required=true) String filename, @RequestParam(value="caseId", required=true) String caseId){
        String path = caseTempPath + File.separator;
        filename = path + filename;
        //unzip
        ZipUtil.unZipFiles(filename, path);
        //search into dir in path to find .xls or .json
        boolean loadSuccess = readOneOfCases(path, Integer.parseInt(caseId));
        //remove all files and dirs in path
        File f = new File(path);
        FileUtil.deleteAll(f);
        if(!f.exists())
            f.mkdir();
        System.out.println("import case clear dir");
        Result res = new Result();
        res.setSuccessful(loadSuccess);
        return res;
    }


    @RequestMapping(value="/downloadCase", method = RequestMethod.GET)
    @ResponseBody
    public Result downloadCase(@RequestParam(value="caseId", required=true) String id){
        //clear
        clearZipAndDir(caseTempPath);
        System.out.println("export case clear dir");
        int caseId = Integer.parseInt(id);
        //create dir, copy file to dir
        buildCaseService.createSpecialDataDir(caseId);
        //create .xls, write .xls
        buildCaseService.createAndWriteExcel(caseId);
        //zip
        Case _case = caseMapper.selectByPrimaryKey(caseId);
        ZipUtil.zipFiles(caseTempPath, basePath+File.separator+_case.getName()+".zip");
        // ready to download
        Result res = new Result();
        res.setSuccessful(true);
        return res;
    }

    @RequestMapping(value="/startCaseDownLoad",method=RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<byte[]> startCaseDownLoad(@RequestParam(value="caseId", required=true) String id, HttpServletRequest request) throws IOException {
        int caseId = Integer.parseInt(id);
        Case _case = caseMapper.selectByPrimaryKey(caseId);
        File file = new File(basePath+File.separator+_case.getName()+".zip");
        HttpHeaders headers=new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        String name = file.getName();
        headers.setContentDispositionFormData("attachment", name);
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);
    }

    private void clearZipAndDir(String filePath){
        File f = new File(filePath);
        FileUtil.deleteAll(f);
        File basepath = new File(basePath);
        File[] files = basepath.listFiles();
        for(File file : files) {
            if (file.isDirectory()) continue;
            else if (file.getName().endsWith(".zip")) {
                file.delete();
            }
        }
        if(!f.exists()) f.mkdir();
    }

    @RequestMapping(value="/downloadCases",method = RequestMethod.GET)
    @ResponseBody
    public Result downloadCases(@RequestParam(value="parentId", required=true) String pId){
        clearZipAndDir(casesTempPath);
        int parentId = Integer.parseInt(pId);
        System.out.println(parentId);
        //create dir, copy file to dir
        buildCaseService.createSpecialDataDirForCases(parentId);
        //create .xls, write .xls
        buildCaseService.createAndWriteExcelForCases(parentId);
        //zip
        //Case _case = caseMapper.selectByPrimaryKey(caseId);
        String casesName = "cases"+pId;
        System.out.println(casesName);
        boolean success = ZipUtil.zipFiles(casesTempPath, basePath+File.separator+casesName+".zip");
        // ready to download
        Result res = new Result();
        res.setSuccessful(success);
        return res;
    }

    @RequestMapping(value="/startCasesDownLoad",method=RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<byte[]> startCasesDownLoad(@RequestParam(value="caseId", required=true) String id, HttpServletRequest request) throws IOException {
        String casesname = "cases"+id;
        File file = new File(basePath+File.separator+casesname+".zip");
        HttpHeaders headers=new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        String name = file.getName();
        headers.setContentDispositionFormData("attachment", name);
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);
    }

    @RequestMapping(value="/uploadMatrix", method=RequestMethod.POST)
    public void uploadMatrix(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) throws IOException{
        String path = "D:\\cw_upload\\matrix";
        upload(multipartRequest, response, path);
    }

    @RequestMapping(value="/readMatrixJson",method=RequestMethod.GET)
    @ResponseBody
    public Result readMatrixJson(@RequestParam(value="filename", required=true) String filename){
        String path = "D:\\cw_upload\\matrix\\";
        filename = path + filename;
        Result res = new Result();
        try {
            BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF-8"));
            StringBuilder sb = new StringBuilder();
            String line = null;

            while((line=bufr.readLine())!=null){
                sb.append(line);
            }
            res.setMessage(sb.toString());
            //System.out.println(res.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }

    @RequestMapping(value="/createMatrixJson",method=RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<byte[]> createMatrixJson(HttpServletRequest request) throws IOException {
        //request.setCharacterEncoding("GBK");
        String matrixJson = request.getParameter("content");
        System.out.println(matrixJson);
        File file=download(matrixJson);
        HttpHeaders headers=new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        String name=file.getName();
        headers.setContentDispositionFormData("attachment",name);
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);
    }

    private File download(String data) throws IOException {
        String originPath = this.getClass().getResource("/").getPath();
        originPath = originPath.substring(0, originPath.indexOf("WEB-INF"));
        originPath = originPath + "download";
        String fileName = "matrix_";
        String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        fileName = fileName + time + ".json";
        File originFile = new File(originPath);
        if (!originFile.exists()) {
            originFile.mkdirs();
        }
        String filePath = originPath + File.separator + fileName;
        File sourceFile = new File(filePath);
        if (!sourceFile.exists()) {
            sourceFile.createNewFile();
        }
        FileOutputStream os = new FileOutputStream(filePath);
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
        writer.write(data);
        writer.close();
        os.close();
        return sourceFile;
    }

    private void upload(MultipartHttpServletRequest multipartRequest, HttpServletResponse response, String path) throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        String result = "";
        try{
            for(Iterator it = multipartRequest.getFileNames();it.hasNext();){
                String key = (String)it.next();
                MultipartFile file = multipartRequest.getFile(key);
                if(file.getOriginalFilename().length()>0){
                    String filename = file.getOriginalFilename();
                    String filepath = path;
                    OutputStream out = new FileOutputStream(new File(filepath+"\\"+filename));
                    //System.out.println(filename);
                    out.write(file.getBytes());
                    out.close();
                }
            }
            result = "{result:'上传成功'}";
        }catch(Exception e){
            result = "{result:'上传失败'}";
            e.printStackTrace();
        }
        response.getWriter().print(result);
    }

    private boolean readOneOfCases(String filePath, int caseId){
        File f = null;
        File[] paths = null;
        String excelPath = null;
        String casePath = null;
        File[] fieldCatalogPaths = null;
        boolean loadSuccess = false;
        try{
            f = new File(filePath);
            paths = f.listFiles();
//            for(File file : paths){
//                if(file.isDirectory()){
//                    f = new File(file.getAbsolutePath());
//                    paths = f.listFiles();
//                }
//            }
            for(File file : paths){
                if(file.isFile() && file.getName().endsWith(".xls")){
                    excelPath = file.getAbsolutePath();
                }else if(file.isDirectory()){
                    casePath = file.getAbsolutePath();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        //read .xls or .json and update database
        loadSuccess = buildCaseService.loadExcel(excelPath, caseId);
//        System.out.println(loadSuccess);
        //search into dir in path to find dirs named file, image, 3D, video
        //copy them to ../file, ../image, ../3D, ../video
        if(loadSuccess){
            Stack<File> stack = new Stack<File>();
            File caseDir = new File(casePath);
            fieldCatalogPaths = caseDir.listFiles();
            for(File fieldCatalogPath : fieldCatalogPaths){
                stack.push(fieldCatalogPath);
            }
            while(!stack.empty()){
                File curDir = stack.pop();
                File[] subDirs = curDir.listFiles();
                for(int i=0;i<subDirs.length;i++){
                    if(subDirs[i].getName().endsWith("_file")){
                        File[] files = subDirs[i].listFiles();
                        String outPath = FilePath + File.separator;
                        for(File file : files){
                            outPath += file.getName();
                            FileUtil.copyFile(file, new File(outPath));
                            outPath = FilePath + File.separator;
                        }
                    }else if(subDirs[i].getName().endsWith("_image")){
                        File[] images = subDirs[i].listFiles();
                        String outPath = imagePath + File.separator;
                        for(File file : images){
                            outPath += file.getName();
                            FileUtil.copyFile(file, new File(outPath));
                            outPath = imagePath + File.separator;
                        }
                    }else if(subDirs[i].getName().endsWith("_3D")){
                        File[] threeDs = subDirs[i].listFiles();
                        String outPath = threeDPath + File.separator;
                        for(File file : threeDs){
                            outPath += file.getName();
                            FileUtil.copyFile(file, new File(outPath));
                            outPath = threeDPath + File.separator;
                        }
                    }else if(subDirs[i].getName().endsWith("_video")){
                        File[] videos = subDirs[i].listFiles();
                        String outPath = videoPath + File.separator;
                        for(File file : videos){
                            outPath += file.getName();
                            FileUtil.copyFile(file, new File(outPath));
                            outPath = videoPath + File.separator;
                        }
                    }else if(subDirs[i].getName().endsWith("_multi")){
                        //read multi html and update database
                        int fieldId = Integer.parseInt(subDirs[i].getName().split("_")[1]);
                        File[] multis = subDirs[i].listFiles();
                        for(File file : multis){
                            String value = FileUtil.readFileToString(file);
                            buildCaseService.updateMultiValue(caseId, fieldId, value);
                        }
                    }else{
                        stack.push(subDirs[i]);
                    }
                }
            }
        }
        return loadSuccess;
    }
}

